package consistence_hash;

import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.TreeMap;
import java.util.stream.IntStream;

public class ConsistenceHash {
    private static final int TIMES = 10000000;
    private static final int NODES = 100;

    @Test
    public void step1() throws NoSuchAlgorithmException {
        int[] nodes = new int[100];
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        IntStream.range(0, TIMES)
                .forEach(i -> {
                    md5.update(String.valueOf(i).getBytes());
                    byte[] digest = md5.digest();
                    BigInteger bigInteger = new BigInteger(1, digest);
                    BigInteger mod = bigInteger.mod(new BigInteger(String.valueOf(NODES)));
                    nodes[mod.intValue()] += 1;
                });

        long ave = TIMES / NODES;
        long maxNodeCount = Arrays.stream(nodes).asLongStream().max().getAsLong();
        long minNodeCount = Arrays.stream(nodes).asLongStream().min().getAsLong();

        System.out.println("ave:" + ave);
        System.out.println("maxNodeCount:" + maxNodeCount + " (" + (maxNodeCount - ave) * 100.0 / ave + ")");
        System.out.println("minNodeCount:" + minNodeCount + " (" +  (ave - minNodeCount) * 100.0 / ave + ")");

    }

    @Test
    public void step2() throws NoSuchAlgorithmException {
        int change = 0;
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        for(int i = 0; i < TIMES; i++) {
            md5.update(String.valueOf(i).getBytes());
            byte[] digest = md5.digest();
            BigInteger bigInteger = new BigInteger(1, digest);
            BigInteger oldMod = bigInteger.mod(new BigInteger(String.valueOf(NODES)));
            BigInteger newMod = bigInteger.mod(new BigInteger(String.valueOf(NODES + 1)));
            if(!oldMod.equals(newMod)) {
                change++;
            }
        }

        System.out.println(change * 100.0 / TIMES);
    }

    @Test
    public void step3() {
        int newArrSize = NODES + 100;
        TreeMap<BigInteger, Object> oriMap = new TreeMap<>();
        TreeMap<BigInteger, Object> newMap = new TreeMap<>();
        BigInteger[] oriArr = new BigInteger[NODES];
        BigInteger[] newArr = new BigInteger[newArrSize];

        IntStream.range(0, NODES)
                .forEach(i -> oriArr[i] = getHashVal(i));

        IntStream.range(0, newArrSize)
                .forEach(i -> newArr[i] = getHashVal(i));


    }

    private BigInteger getHashVal(int val) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(String.valueOf(val).getBytes());
        byte[] digest = md5.digest();
        return new BigInteger(1, digest);
    }
}
